]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
Fix hover state after DND
authorOwen W. Taylor <otaylor@fishsoup.net>
Sun, 30 Jan 2011 22:39:50 +0000 (17:39 -0500)
committerOwen W. Taylor <otaylor@fishsoup.net>
Mon, 7 Mar 2011 21:53:56 +0000 (16:53 -0500)
During a drag-and-drop, our pointer grab keeps enter/leave events from
being delivered. That means that after the DND ends, whatever actor is
under the pointer won't have received the enter event it should have,
and any state or hover effect dependent on that won't work right.
By paying attention to the actors we leave and enter we can figure out
what widgets we need to call st_widget_sync_hover() on after the drag.

https://bugzilla.gnome.org/show_bug.cgi?id=640974

js/ui/dnd.js

index 61776da913ec86d9c2c2d4f1b32353484a121978..a755057f1b71967ea4be56f07d9366656088d31d 100644 (file)
@@ -87,6 +87,10 @@ _Draggable.prototype = {
 
         this.actor.connect('destroy', Lang.bind(this, function() {
             this._actorDestroyed = true;
+            // If the drag actor is destroyed and we were going to fix
+            // up its hover state, fix up the parent hover state instead
+            if (this.actor == this._firstLeaveActor)
+                this._firstLeaveActor = this._dragOrigParent;
             if (this._dragInProgress)
                 this._cancelDrag(global.get_current_time());
             this.disconnectAll();
@@ -101,6 +105,12 @@ _Draggable.prototype = {
         this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
         this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
 
+        // During the drag, we eat enter/leave events so that actors don't prelight or show
+        // tooltips. But we remember the actors that we first left/last entered so we can
+        // fix up the hover state after the drag ends.
+        this._firstLeaveActor = null;
+        this._lastEnterActor = null;
+
         this._eventsGrabbed = false;
     },
 
@@ -200,6 +210,11 @@ _Draggable.prototype = {
                 this._cancelDrag(event.get_time());
                 return true;
             }
+        } else if (event.type() == Clutter.EventType.LEAVE) {
+            if (this._firstLeaveActor == null)
+                this._firstLeaveActor = event.get_source();
+        } else if (event.type() == Clutter.EventType.ENTER) {
+            this._lastEnterActor = event.get_source();
         }
 
         return false;
@@ -487,7 +502,7 @@ _Draggable.prototype = {
         if (this._actorDestroyed) {
             global.unset_cursor();
             if (!this._buttonDown)
-                this._ungrabEvents();
+                this._dragComplete();
             this.emit('drag-end', eventTime, false);
             return;
         }
@@ -544,12 +559,36 @@ _Draggable.prototype = {
             this._dragComplete();
     },
 
+    // Actor is an actor we have entered or left during the drag; call
+    // st_widget_sync_hover on all StWidget ancestors
+    _syncHover: function(actor) {
+        while (actor) {
+            let parent = actor.get_parent();
+            if (actor instanceof St.Widget)
+                actor.sync_hover();
+
+            actor = parent;
+        }
+    },
+
     _dragComplete: function() {
-        Shell.util_set_hidden_from_pick(this._dragActor, false);
+        if (!this._actorDestroyed)
+            Shell.util_set_hidden_from_pick(this._dragActor, false);
+
+        this._ungrabEvents();
+
+        if (this._firstLeaveActor) {
+            this._syncHover(this._firstLeaveActor);
+            this._firstLeaveActor = null;
+        }
+
+        if (this._lastEnterActor) {
+            this._syncHover(this._lastEnterActor);
+            this._lastEnterActor = null;
+        }
 
         this._dragActor = undefined;
         currentDraggable = null;
-        this._ungrabEvents();
     }
 };